MybatisPlus 主键为自增id时根据特定多字段判断是否在数据库内存在该条记录,存在则更新、不存在则插入 | 您所在的位置:网站首页 › mybatisplus 联合主键 › MybatisPlus 主键为自增id时根据特定多字段判断是否在数据库内存在该条记录,存在则更新、不存在则插入 |
目录 需求 单主键校验 非主键多字段校验 多主键校验 需求主键字段使用了自增id做了优化,但是需求需要依赖两个联合唯一的字段校验该条记录是否存在,如果存在则执行更新操作,不存在则执行插入操作。 单主键校验一开始打算手写sql,使用SelcetKey + foreach 先根据两个字段查出对应的id,如果id不存在则插入,否则更新,但是底层是单条多次的sql提交,很影响性能。 后来发现的ServiceImpl类下有一个saveOrUpdateBatch方法: @Transactional( rollbackFor = {Exception.class} ) public boolean saveOrUpdateBatch(Collection entityList, int batchSize) { TableInfo tableInfo = TableInfoHelper.getTableInfo(this.entityClass); Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]); String keyProperty = tableInfo.getKeyProperty(); Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!", new Object[0]); return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, this.log, entityList, batchSize, (sqlSession, entity) -> { Object idVal = ReflectionKit.getFieldValue(entity, keyProperty); return StringUtils.checkValNull(idVal) || CollectionUtils.isEmpty(sqlSession.selectList(this.getSqlStatement(SqlMethod.SELECT_BY_ID), entity)); }, (sqlSession, entity) -> { ParamMap param = new ParamMap(); param.put("et", entity); sqlSession.update(this.getSqlStatement(SqlMethod.UPDATE_BY_ID), param); }); }看起来已经帮我们封装好了,但是它针对的是单主键的校验,我们的主键是数据库自增的,需要校验的是非主键字段,不太适用。 非主键多字段校验(主要)最终优化了一下代码,直接在Service实现里调用即可: public boolean saveOrUpdateBatch2(List list, int batchSize) { return SqlHelper.executeBatch(entityClass, log, list, batchSize, (sqlSession, entity) -> { HashMap param = new HashMap(); LambdaQueryWrapper eq = Wrappers.lambdaQuery() .eq(XXXModel::getXXX1, entity.getXXX1()) .eq(XXXModel::getXXX2, entity.getXXX2()); param.put("ew", eq); XXXModelmodel = sqlSession.selectOne(getSqlStatement(SqlMethod.SELECT_ONE), param); if (model == null) { sqlSession.insert(getSqlStatement(SqlMethod.INSERT_ONE), entity); } else { entity.setId(model.getId()); param.put("et",entity); sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param); } }); }先查一次数据,判断是否存在,不存在则插入,存在则根据查到的id主键更新。 批量操作时,底层会把sql先缓存在SqlSession内,调用sqlSession.flushStatements()时才会把数据发到数据库执行: public static boolean executeBatch(Class entityClass, Log log, Collection list, int batchSize, BiConsumer consumer) { Assert.isFalse(batchSize < 1, "batchSize must not be less than one", new Object[0]); return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, (sqlSession) -> { int size = list.size(); int i = 1; for(Iterator var6 = list.iterator(); var6.hasNext(); ++i) { E element = var6.next(); consumer.accept(sqlSession, element); if (i % batchSize == 0 || i == size) { //满足一个batchSize 或 传入大小不足一个batchSize时 批处理提交 sqlSession.flushStatements(); } } }); }需要注意的是,如果不使用SqlSession而是直接使用baseMapper来查会报空指针异常,日志也没有打印堆栈信息,异常在底层被捕获了又抛出。(个人猜测跟SqlSession的底层封装有关,一个会话内的sql必须要依赖同一个SqlSession执行) 多主键校验联合主键的批量插入or更新其实有MppBaseMapper针对原生的BaseMapper做了实现,如果表结构为联合主键,可以分别继承MppBaseMapper、IMppService直接调用即可。具体代码为MppServiceImpl:saveOrUpdateBatchByMultiId(): @Transactional( rollbackFor = {Exception.class} ) public boolean saveOrUpdateBatchByMultiId(Collection entityList, int batchSize) { TableInfo tableInfo = TableInfoHelper.getTableInfo(this.entityClass); Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]); //这里面其实是获取实体类中使用了MppMultiId注解的字段映射为Map 这个字段是Mpp用来用于标识多个主键的 Map idMap = this.checkIdCol(this.entityClass, tableInfo); Assert.notEmpty(idMap, "entity {} not contain MppMultiId anno", new Object[]{this.entityClass.getName()}); return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> { boolean updateFlag = true; Iterator var6 = idMap.keySet().iterator(); while(var6.hasNext()) { String attr = (String)var6.next(); //校验主键是否为空 为空则不更新 if (StringUtils.checkValNull(attr)) { updateFlag = false; break; } } //走到此处 说明主键均不为空 接着查数据库判断该记录是否存在 if (updateFlag) { Object obj = this.selectByMultiId(entity); if (Objects.isNull(obj)) { updateFlag = false; } } //更新或插入 if (updateFlag) { ParamMap param = new ParamMap(); param.put("et", entity); sqlSession.update(tableInfo.getSqlStatement("updateByMultiId"), param); } else { sqlSession.insert(tableInfo.getSqlStatement(SqlMethod.INSERT_ONE.getMethod()), entity); } }); } |
CopyRight 2018-2019 实验室设备网 版权所有 |